package com.aphrodite.ui.screens;

import java.util.Vector;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;

import com.aphrodite.ui.bg.Background;
import com.aphrodite.ui.widgets.TraversableWidget;
import com.aphrodite.ui.widgets.Widget;

/**
 * A High level display abstraction used to render aphordite widgets
 * <p>
 * Provides flexible routines for manipulating the layout, Z-ordering and
 * display of widgets added to the screen.
 * </p>
 * 
 * @author kentelt
 * 
 */
public class AphroScreen extends Canvas {

	public final static byte LAYOUT_VERTICAL = 1;
	private Background bg;
	private int bgColor = 0xffffff;
	private int estateX;
	private int estateY;
	private TraversableWidget inFocusWidget;
	private String title;
	private int titleEnd;
	private int titleFGcolor;

	private Font titleFont;
	private int titleHeight;

	private int titleStart;
	private final Vector widgets = new Vector();

	public AphroScreen() {

	}

	public AphroScreen(String title) {
		setTitle(title, Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_SMALL), 0xffffff, 0xA0A0A0,
				0x303030);
	}

	/**
	 * Add a new widget to the screen
	 * 
	 * @param widget
	 */
	public void addWidget(Widget widget) {
		widget.setY(widget.getY() + titleHeight);
		widgets.addElement(widget);
		repaint();
	}

	/**
	 * Add widget with Z-ordering.
	 * <p>
	 * Adds <code>newWidget</code> behind <code>existWidget</code>. However,
	 * there is no guarantee that <code>existWidget</code> will completely hide
	 * <code>newWidget</code> if its dimensions are greater.
	 * </p>
	 * 
	 * @param newWidget
	 * @param existWidget
	 * @throws IllegalArgumentException
	 *             if <code>existWidget</code> is not present
	 */
	public void addWidgetBehind(Widget newWidget, Widget existWidget) {
		int idx;
		if ((idx = widgets.indexOf(existWidget)) != -1) {
			widgets.insertElementAt(newWidget, idx > 0 ? idx - 1 : idx);
		} else {
			throw new IllegalArgumentException("Widget not added to screen");
		}
	}

	public void addWidgetOnTop(Widget newWidget, Widget existWidget) {
		int idx;
		if ((idx = widgets.indexOf(existWidget)) != -1) {
			if (idx != widgets.size() && idx > 0) {
				widgets.insertElementAt(newWidget, idx + 1);
			} else
				widgets.addElement(newWidget);
		} else {
			throw new IllegalArgumentException("Widget not added to screen");
		}
	}

	/**
	 * Hide a given widget
	 * 
	 * @param widget
	 *            Widget to be hidden
	 * 
	 */
	public void hideWidget(Widget widget) {
		toogleVisible(widget, false);
	}

	protected void keyPressed(int keycode) {
		int keyCode = getGameAction(keycode);
		switch (keyCode) {
		case Canvas.UP:
			scroll(-10);
			break;
		case Canvas.DOWN:
			scroll(10);
			break;
		}
	}

	protected void keyReleased(int keycode) {
		if (inFocusWidget != null) {
			inFocusWidget.keyPressed(getGameAction(keycode), keycode);
		}
	}

	protected void keyRepeated(int keycode) {

	}

	protected void paint(Graphics g) {
		/* Render the background */
		if (bg == null) {
			g.setColor(bgColor);
			g.fillRect(0, 0, getWidth(), getHeight());
		} else {
			bg.render(g);
		}
		/* Render the widgets */
		Widget widget = null;
		for (int i = 0; i < widgets.size(); i++) {
			widget = (Widget) widgets.elementAt(i);
			/* Only render widgets that are visible */
			if (widget.getY() + widget.getHeight() > 0 && widget.getY() < getHeight()) {
				widget.render(g);
			} else
				System.out.println("Widget not rendered");
		}
		/* Render the title */
		if (title != null) {
			// TODO change to Gradient class
			com.aphrodite.ui.graphics.GraphicEffects.drawGradientRect(g, titleStart, titleEnd, false, 0, 0, getWidth(),
					titleHeight);
			g.setColor(titleFGcolor);
			g.setFont(titleFont);
			g.drawString(title, 2, 2, 0);
		}
	}

	protected void pointerDragged(int x, int y) {
		for (int i = 0; i < widgets.size(); i++) {
			Widget widget = (Widget) widgets.elementAt(i);
			if (widget instanceof TraversableWidget) {
				((TraversableWidget) widget).pointerDrag(x, y);
			}
		}
	}

	protected void pointerPressed(int x, int y) {
		for (int i = 0; i < widgets.size(); i++) {
			Widget widget = (Widget) widgets.elementAt(i);
			if (widget instanceof TraversableWidget) {
				((TraversableWidget) widget).pointerPress(x, y);
			}
		}
	}

	protected void pointerReleased(int x, int y) {
		for (int i = 0; i < widgets.size(); i++) {
			Widget widget = (Widget) widgets.elementAt(i);
			if (widget instanceof TraversableWidget) {
				((TraversableWidget) widget).pointerRelease(x, y);
			}
		}
	}

	public void removeAllWidgets() {
		widgets.removeAllElements();
		repaint();
	}

	/**
	 * Remove the given widget from the screen
	 * 
	 * @param widget
	 */
	public void removeWidget(Widget widget) {
		// TODO we need to adjust the screen if not a blank space is seen
		widgets.removeElement(widgets);
		repaint();
	}

	/**
	 * Redo the layout of the widgets according to the current layout strategy
	 */
	private void repack() {

	}

	private void scroll(int delta) {
		for (int i = 0; i < widgets.size(); i++) {
			Widget widget = (Widget) widgets.elementAt(i);
			widget.setY(widget.getY() + delta);
		}
	}

	/**
	 * Set a background for the screen
	 * 
	 * @param bg
	 *            The any type of background. If
	 *            <code>null<code> the background color is rendered
	 * @see AphroScreen#setBGcolor(int)
	 */
	public void setBackground(Background bg) {
		if (bg != null) {
			bg.setX(0);
			bg.setY(0);
			bg.setWidth(getWidth());
			bg.setHeight(getHeight());
		}
		this.bg = bg;
	}

	/**
	 * Set the background color of this screen. <p> The background color will
	 * not be rendered if {@link AphroScreen#setBackground(Background)} is set.
	 * </p>
	 * 
	 * @see AphroScreen#setBackground(Background)
	 * 
	 * @param color
	 */
	public void setBGcolor(int color) {
		this.bgColor = color;
	}

	public void setTitle(String title, Font titleFont, int titleFGcolor, int startColor, int endColor) {
		this.title = title;
		this.titleStart = startColor;
		this.titleEnd = endColor;
		this.titleFGcolor = titleFGcolor;
		this.titleFont = titleFont;
		this.titleHeight = titleFont.getHeight() + 4;
		repaint();
	}

	protected void showNotify() {
		Widget.init(this);
	}

	public void showWidget(Widget widget) {
		toogleVisible(widget, true);
	}

	private void toogleVisible(Widget widget, boolean isVisible) {
		int idx = widgets.indexOf(widget);
		if (idx != -1) {
			((Widget) widgets.elementAt(idx)).setVisible(isVisible);
			repack();
		}
	}
}
